package sdk

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"dgo/goutils/yhttp"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"io/ioutil"
	"strings"
)

const (
	VX_API_JSCODE2_SESSION = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"
)

type VxXcxUtil struct {
	AppId     string
	AppSecret string
}

func NewVxXcxUtil() *VxXcxUtil {
	ins := &VxXcxUtil{}
	return ins
}

/*
*

	{
	      "appid": "wxe242a8220a1cbf0a",
	      "appsecret": "2552cf7558f7df4118de0c199a9668b2"
	}
*/
func (this *VxXcxUtil) ReloadConf(conf *wrapper.SuperValue) {
	if conf == nil {
		return
	}
	conf.CheckExistsStrFunc("appid", func(strv string) {
		this.AppId = strv
	})

	conf.CheckExistsStrFunc("appsecret", func(strv string) {
		this.AppSecret = strv
	})
}

/*
*
onresult(data)

	openid	string	用户唯一标识
	session_key	string	会话密钥
	unionid	string	用户在开放平台的唯一标识符，若当前小程序已绑定到微信开放平台帐号下会返回，详见 UnionID 机制说明。
	errcode	number	错误码
	errmsg	string	错误信息

errcode 的合法值

	值	说明	最低版本
	-1	系统繁忙，此时请开发者稍候再试
	0	请求成功
	40029	code 无效
	45011	频率限制，每个用户每分钟100次
	40226	高风险等级用户，小程序登录拦截 。风险等级详见用户安全解方案
*/
func (this *VxXcxUtil) GetOpenId(rescode string, onresult func(data *wrapper.SuperValue, err error)) {
	// doc: https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html#请求地址
	data, err := this.GetOpenIdEx(rescode)
	onresult(data, err)
}

/*
*
{"session_key":"WsmrmtzqIHp1WUvLpyvUJg==","openid":"ovVN45HwuDpEkVif_zQ8NE1dRX64"}
*/
func (this *VxXcxUtil) GetOpenIdEx(rescode string) (data *wrapper.SuperValue, rerr error) {
	// doc: https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html#请求地址
	// doc: https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html#调用示例
	resp, err := yhttp.DefaultHttpGet(fmt.Sprintf(VX_API_JSCODE2_SESSION, this.AppId, this.AppSecret, rescode))
	if err != nil {
		rerr = err
		return
	} else {
		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			rerr = err
			return
		}
		json, err := wrapper.NewSVFromBuf(body)
		if err != nil {
			rerr = fmt.Errorf("解析响应数据[%s]出现异常:%s", string(body), err.Error())
			return
		}
		data = json
	}
	return
}

func (this *VxXcxUtil) DecryptData(sessionKey, iv, encryptedData string) (map[string]interface{}, error) {
	if len := strings.Count(sessionKey, "") - 1; len != 24 {
		return nil, errors.New("无效值session_key")
	}
	aesKey, err := base64.StdEncoding.DecodeString(sessionKey)
	if err != nil {
		return nil, err
	}

	if len := strings.Count(iv, "") - 1; len != 24 {
		return nil, errors.New("无效值iv")
	}
	ivKey, err := base64.StdEncoding.DecodeString(iv)
	if err != nil {
		return nil, err
	}

	decodeData, err := base64.StdEncoding.DecodeString(encryptedData)
	if err != nil {
		return nil, err
	}

	//fmt.Println(decodeData, aesKey, ivKey)
	dataBytes, err := this.AesDecrypt(decodeData, aesKey, ivKey)
	if err != nil {
		return nil, err
	}

	var result map[string]interface{}
	dataBytes = bytes.TrimPrefix(dataBytes, []byte("\xef\xbb\xbf"))
	err = json.Unmarshal(dataBytes, &result)
	//fmt.Println(err)
	//fmt.Println(dataBytes)
	//fmt.Println(result)
	if err != nil {
		return nil, err
	}
	//watermark := result["watermark"].(map[string]interface{})
	//if watermark["appid"] != appId {
	//	return nil, errors.New("无效的appid数据")
	//}

	return result, err
}

func (this *VxXcxUtil) AesDecrypt(crypted, key, iv []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	blockMode := cipher.NewCBCDecrypter(block, iv)
	origData := make([]byte, len(crypted))
	blockMode.CryptBlocks(origData, crypted)

	// 去除填充
	length := len(origData)
	unp := int(origData[length-1])
	if length < unp {
		return nil, errors.New("数据异常,解码失败")
	}
	data := origData[:(length - unp)]
	return data, nil
}
